#include <sys/sem.h>
#include <signal.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include "lock.h"
#include "benchapi.h"

int flock_init (char *lock_template)
{
    int ret_fd = mkstemp (lock_template);
    if (ret_fd < 0)
        ERROR_RETURN (("mkstemp %s error, %m", lock_template), -1);

    unlink (lock_template);
    return ret_fd;
}

int file_unlock (int fd, int offset)
{
    struct flock unlock_it;
    int     rc;

    unlock_it.l_type = F_UNLCK;
    unlock_it.l_whence = SEEK_SET;
    unlock_it.l_start = offset;
    unlock_it.l_len = 1;    

    while ( (rc = fcntl(fd, F_SETLKW, &unlock_it)) < 0) {
        if (errno == EINTR)
            continue;
        else 
            ERROR_RETURN (("funlock error,fd=%d,offset=%d, %m", fd, offset), -1);
    }

    return 0;
}

int file_rlock (int fd, int offset)
{
    struct flock lock_it;
    int     rc;

    lock_it.l_type = F_RDLCK;
    lock_it.l_whence = SEEK_SET;
    lock_it.l_start = offset;
    lock_it.l_len = 1;  

    if ( (rc = fcntl(fd, F_SETLKW, &lock_it)) < 0) {
        if (errno != EINTR)
            ERROR_LOG ("flock error,fd=%d,offset=%d, %m", fd, offset);
        return -1;
    }

    return 0;
}

int file_wlock (int fd, int offset)
{
    struct flock lock_it;
    int     rc;

    lock_it.l_type = F_WRLCK;
    lock_it.l_whence = SEEK_SET;
    lock_it.l_start = offset;
    lock_it.l_len = 1;  

    if ( (rc = fcntl(fd, F_SETLKW, &lock_it)) < 0) {
        if (errno != EINTR)
            ERROR_LOG ("flock error,fd=%d,offset=%d, %m", fd, offset);
        return -1;
    }

    return 0;
}

int sem_init ()
{
    int ret_semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0664);
    if (ret_semid != -1) {
        union semun arg;
        arg.val = 1;
        semctl (ret_semid, 0, SETVAL, arg);
    } else {
        ERROR_LOG ("%s", "semget error, %m");
    }

    return ret_semid;
}

int sem_unlock (int semid)
{
    struct sembuf op;
    op.sem_num = 0;
    op.sem_flg = SEM_UNDO;
    op.sem_op = 1;
    while (semop (semid, &op, 1) == -1) {
        if (errno != EINTR)
            ERROR_LOG ("semop %d error, %m", semid);
    }

    return 0;
}

int sem_lock (int semid)
{
    struct sembuf op;
        
    op.sem_num = 0;
    op.sem_flg = SEM_UNDO;
    op.sem_op = -1;
        
    if (semop (semid, &op, 1) == -1){
        if (errno != EINTR)
            ERROR_LOG ("semop %d error, %m", semid);
        return -1;
    }
        
    return 0;
}
